--[[ SLDataText Copyright (c) 2008, Jeff "Taffu" Fancher <jdfancher@gmail.com> All rights reserved. ]]
-- Version: 2.1.4 -- Rev Date: 11/09/2008

local SLDataText = LibStub("AceAddon-3.0"):GetAddon("SLDataText")
local L = LibStub("AceLocale-3.0"):GetLocale("SLDataText")
local media = LibStub("LibSharedMedia-3.0")
local justTable, strataTable, pointTable = SLDataText.just, SLDataText.strata, SLDataText.point
local db, charDB

local MODNAME = "Statline"
local Statline = SLDataText:NewModule(MODNAME, "AceEvent-3.0")

local dispTbl = {
    ["Armor Rating"] = L["Armor Rating"],
    ["Attack Power"] = L["Attack Power"],
    ["Block Chance"] = L["Block Chance"],
    ["Crit Chance"] = L["Crit Chance"],
    ["Damage Per Second"] = L["Damage Per Second"],
    ["Defense Rating"] = L["Defense Rating"],
    ["Dodge Chance"] = L["Dodge Chance"],
    ["Expertise Percentage"] = L["Expertise Percentage"],
    ["Hit Rating"] = L["Hit Rating"],
    ["Mana Regen Casting"] = L["Mana Regen Casting"],
    ["Parry Chance"] = L["Parry Chance"],
    ["Ranged Attack Power"] = L["Ranged Attack Power"],
    ["Ranged Crit Chance"] = L["Ranged Crit Chance"],
    ["Spell Bonus Healing"] = L["Spell Bonus Healing"],
    ["Spell Crit Chance"] = L["Spell Crit Chance"],
    ["Spell Damage"] = L["Spell Damage"],
    ["Spell Penetration"] = L["Spell Penetration"],
}

local function fetchStats(stat)
    local color = SLDataText:GetColor()
    if ( stat == L["Armor Rating"] ) then
        local _, _, base, bonus, minus = UnitArmor("player")
        stat = format("%s|cff%sArmor|r", base + bonus - minus, color)
    elseif ( stat == L["Attack Power"] ) then
        local base, pos, neg = UnitAttackPower("player")
        stat = format("%s|cff%sAP|r", base + pos - neg, color)
    elseif ( stat == L["Block Chance"] ) then
        local block = GetBlockChance()
        stat = format("%.1f%%|cff%sBlock|r", block, color)
    elseif ( stat == L["Crit Chance"] ) then
        local critChance = GetCritChance()
        stat = format("%.1f%%|cff%sCrit|r", critChance, color)
    elseif ( stat == L["Damage Per Second"] ) then
        local speed, offhandSpeed = UnitAttackSpeed("player")
        local minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent = UnitDamage("player")
        minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg
        maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg
        local baseDamage = (minDamage + maxDamage) * 0.5
        local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent
        local damagePerSecond = (max(fullDamage,1) / speed)
        stat = format("%.1f|cff%sDPS|r", damagePerSecond, color)
    elseif ( stat == L["Defense Rating"] ) then
        local def, armDef = UnitDefense("player")
        stat = format("%s|cff%sDef|r", def, color)
    elseif ( stat == L["Dodge Chance"] ) then
        local dodge = GetDodgeChance()
        stat = format("%.1f%%|cff%sDodge|r", dodge, color)
    elseif ( stat == L["Expertise Percentage"] ) then
        local expertisePerc = GetExpertisePercent()
        stat = format("%.1f%%|cff%sExp|r", expertisePerc, color)
    elseif ( stat == L["Mana Regen Casting"] ) then
        local base, combat = GetManaRegen()
        stat = format("%s|cff%sMP5|r", floor(combat*5), color)
    elseif ( stat == L["Hit Rating"] ) then
        local hitRating = GetCombatRating(6)
        stat = format("%s|cff%sHit|r", hitRating, color)
    elseif ( stat == L["Parry Chance"] ) then
        local parry = GetParryChance()
        stat = format("%.1f%%|cff%sParry|r", parry, color)
    elseif ( stat == L["Ranged Attack Power"] ) then
        local base, pos, neg = UnitRangedAttackPower("player")
        stat = format("%s|cff%sRAP|r", base + pos - neg, color)
    elseif ( stat == L["Ranged Crit Chance"] ) then
        local rCrit = GetRangedCritChance()
        stat = format("%.1f%%|cff%sRCrit|r", rCrit, color)
    elseif ( stat == L["Spell Bonus Healing"] ) then
        local heal = GetSpellBonusHealing()
        stat = format("%s|cff%sSpHeal|r", heal, color)
    elseif ( stat == L["Spell Crit Chance"] ) then
        local minCrit = GetSpellCritChance(2)
        for i = 3, 7 do
            local spCrit = GetSpellCritChance(i)
            if ( spCrit < minCrit ) then
                minCrit = spCrit
            end
        end
        stat = format("%.1f%%|cff%sSpCrit|r", minCrit, color)
    elseif ( stat == L["Spell Damage"] ) then
        local minDmg = GetSpellBonusDamage(2)
        for i = 3, 7 do
            local spDmg = GetSpellBonusDamage(i)
            if ( spDmg < minDmg ) then
                minDmg = spDmg
            end
        end
        stat = format("%s|cff%sSpDmg|r", minDmg, color)
    elseif ( stat == L["Spell Penetration"] ) then
        local pen = GetSpellPenetration()
        stat = format("%s|cff%sSpPen|r", pen, color)
    end
    return stat
end

local optGetter, optSetter
do
	function optGetter(info)
		local key = info[#info]
		return db[key]
	end

	function optSetter(info, value)
		local key = info[#info]
		db[key] = value
        SLDataText:RefreshModule(Statline)
	end
end

local options
local function getOptions()
	if not options then options = {
        type = "group",
        name = L["Statline"],
        arg = MODNAME,
        get = optGetter,
        set = optSetter,
        args = {
            genHeader = {
                type = "header",
                name = L["GenSLSet"],
                order = 25,
            },
            enabled = {
                type = "toggle",
                name = L["Enabled"],
                desc = L["EnabledDesc"],
                get = function() return SLDataText:GetModuleEnabled(MODNAME) end,
                set = function(info, value) 
                    SLDataText:SetModuleEnabled(MODNAME, value)
                    if ( SLDataText:GetModuleEnabled(MODNAME) ) then
                        Statline:PLAYER_ENTERING_WORLD()
                    end
                end,
                order = 50,
            },
            noCombatHide = {
                type = "toggle",
                name = L["SIC"],
                desc = L["SICDesc"],
                order = 100,
            },
            dispHeader = {
                type = "header",
                name = L["DispSet"],
                order = 125,
            },
            stat1 = {
                type = "select",
                name = L["Stat1"],
                desc = L["Stat1Desc"],
                values = dispTbl,
                get = function() return charDB.stat1 end,
                set = function(_, val) charDB.stat1 = val Statline:Refresh() end,
                width = "double",
                order = 150,
            },
            stat2 = {
                type = "select",
                name = L["Stat2"],
                desc = L["Stat2Desc"],
                values = dispTbl,
                get = function() return charDB.stat2 end,
                set = function(_, val) charDB.stat2 = val Statline:Refresh() end,
                width = "double",
                order = 175,
            },
            stat3 = {
                type = "select",
                name = L["Stat3"],
                desc = L["Stat3Desc"],
                values = dispTbl,
                get = function() return charDB.stat3 end,
                set = function(_, val) charDB.stat3 = val Statline:Refresh() end,
                width = "double",
                order = 200,
            },
            useGlobalFont = {
                type = "toggle",
                name = L["UseGblFont"],
                desc = L["UseGblFontDesc"],
                order = 300,
            },
            useGlobalFontSize = {
                type = "toggle",
                name = L["UseGblFSize"],
                desc = L["UseGblFSizeDesc"],
                order = 350,
            },
            fontFace = {
                type = "select",
                name = L["Font"],
                desc = L["FontDesc"],
                disabled = function()
                    local isTrue
                    if ( db.useGlobalFont ) then isTrue = true else isTrue = false end
                    return isTrue
                end,
                values = media:List("font"),
                get = function()
                    for k, v in pairs(media:List("font")) do
                        if db.fontFace == v then
                            return k
                        end
                    end
                end,
                set = function(_, font)
                    local list = media:List("font")
                    db.fontFace = list[font]
                    SLDataText:RefreshModule(Statline)
                end,
                width = "double",
                order = 600,
            },
            fontSize = {
                type = "range",
                name = L["FontSize"],
                desc = L["FontSizeDesc"],
                disabled = function()
                    local isTrue
                    if ( db.useGlobalFontSize ) then isTrue = true else isTrue = false end
                    return isTrue
                end,
                min = 6, max = 36, step = 1,
                width = "double",
                order = 650,
            },
            posHeader = {
                type = "header",
                name = L["LaySet"],
                order = 700,
            },
            justify = {
                type = "select",
                name = L["TextJust"],
                desc = L["TextJustDesc"],
                values = justTable,
                width = "double",
                order = 750,
            },
            anchor = {
                type = "input",
                name = L["ParFrm"],
                desc = L["ParFrmDesc"],
                get = function() return db.anchor end,
                width = "double",
                order = 800,
            },
            anchorFrom = {
                type = "select",
                name = L["AnchFrom"],
                desc = L["AnchFromDesc"],
                values = pointTable,
                get = function() return db.anchorFrom end,
                width = "double",
                order = 900,
            },
            offX = {
                type = "input",
                name = L["XOff"],
                desc = L["XOffDesc"],
                get = function() return tostring(db.offX) end,
                width = "double",
                order = 1000,
            },
            offY = {
                type = "input",
                name = L["YOff"],
                desc = L["YOffDesc"],
                get = function() return tostring(db.offY) end,
                width = "double",
                order = 1100,
            },
            strata = {
                type = "select",
                name = L["Strata"],
                desc = L["StrataDesc"],
                values = strataTable,
                width = "double",
                order = 1600,
            },
        },
    }
	end
	
	return options
end

local function buildModule(self)
    if ( not self.frame ) then self.frame = CreateFrame("Frame", "SLDT_Statline", UIParent) end -- The frame
    -- if ( not self.button ) then self.button = CreateFrame("Button", nil, self.frame) end -- The button (optional)
    if ( not self.string ) then self.string = self.frame:CreateFontString(nil, "OVERLAY") end -- The font string
    
    -- Set scripts/etc.
    
    Statline:RegisterEvent("PLAYER_ENTERING_WORLD")
end

function Statline:PLAYER_ENTERING_WORLD()
    SLDataText:RefreshModule(self)
    self:UnregisterEvent("PLAYER_ENTERING_WORLD")
end

function Statline:UNIT_INVENTORY_CHANGED()
    if ( arg1 == "player" ) then
        self:Refresh()
    end
end

function Statline:UNIT_AURA()
    if ( arg1 == "player" ) then
        self:Refresh()
    end
end

function Statline:OnInitialize()
	self.db = SLDataText.db:RegisterNamespace(MODNAME)
    -- Register your modules default settings
    self.db:RegisterDefaults({
        profile = {
            noCombatHide = false,
            fontFace = "Arial Narrow",
            useGlobalFont = true,
            fontSize = 12,
            useGlobalFontSize = true,
            justify = "CENTER",
            anchorPoint = "CENTER", 
            anchor = "UIParent", 
            anchorFrom = "CENTER", 
            offX = -200, 
            offY = 60,
            strata = "BACKGROUND",
        },
        char = {
            stat1 = "Attack Power",
            stat2 = "Crit Chance",
            stat3 = "Hit Rating",
        },
    })
	db = self.db.profile
    charDB = self.db.char
    
    if ( not self.isMoving ) then self.isMoving = false end
	self:SetEnabledState(SLDataText:GetModuleEnabled(MODNAME))
	SLDataText:RegisterModuleOptions(MODNAME, getOptions)
end

function Statline:OnEnable()
    -- Register any events, and hide elements you don't want shown
    self:RegisterEvent("UNIT_INVENTORY_CHANGED")
    self:RegisterEvent("UNIT_AURA")
    -- self:RegisterEvent("PLAYER_AURAS_CHANGED")
    
    buildModule(self)
    if ( not self.frame:IsShown() ) then self.frame:Show() end
end

function Statline:OnDisable()
    -- Unregister any events, nil scripts, and show elements you've hidden
    self:UnregisterEvent("UNIT_INVENTORY_CHANGED")
    self:UnregisterEvent("UNIT_AURA")
    -- self:UnregisterEvent("PLAYER_AURAS_CHANGED")
    self:UnregisterEvent("PLAYER_ENTERING_WORLD")
	if ( self.frame:IsShown() ) then self.frame:Hide() end
end

-- Main update, used to refresh your modules data
function Statline:Refresh()
    -- Gather your data
    local stat1, stat2, stat3
    for key, stat in pairs(charDB) do
        if ( key == "stat1" ) then
            stat1 = fetchStats(stat)
        elseif ( key == "stat2" ) then
            stat2 = fetchStats(stat)
        elseif ( key == "stat3" ) then
            stat3 = fetchStats(stat)
        end
    end
    
    -- Here we fetch the color, determine any display options, and set the value of the module data
    self.string:SetFormattedText("%s %s %s", stat1, stat2, stat3)
    
    -- And then update the module for refreshing/resizing text/frame
    SLDataText:UpdateModule(self)
end